#include "DeterminantCalculator.h"
#include "Math.h"

double DeterminantCalculator::calculate (const Matrix& sourseMatrix)
{
	Matrix matrix = sourseMatrix;

	double determinantSign = 1.0;
	for(size_t i = 0; i < matrix.getRowsCount() - 1; i++)
	{
		size_t pivot = findPivotInColumn(i, matrix);
		if(pivot != i)
		{
			determinantSign *= -1;
			matrix.exchangeRows(i, pivot);

		}
		if(Math::isEqual(0.0, matrix[i][i]))
		{
			return 0.0;
		}
		settingToZeroColumnElements(i, matrix);
	}
	double determinant = determinateOfTriangleMatrix(matrix) * determinantSign;
	return determinant;
}

size_t DeterminantCalculator::findPivotInColumn(size_t startRow, const Matrix& matrix) {
	size_t pivot = startRow;
	for(size_t j = startRow + 1; j < matrix.getRowsCount(); j++)
	{
		if(fabs(matrix[j][startRow]) > fabs(matrix[pivot][startRow]))
		{
			pivot = j;
		}
	}

	return pivot;
}

void DeterminantCalculator::settingToZeroColumnElements( size_t startRow, const Matrix& matrix) {
	for (size_t j = startRow + 1; j <  matrix.getRowsCount(); j++)
	{

		double t = matrix[j][startRow] / matrix[startRow][startRow];
		for(size_t k = 0; k < matrix.getRowsCount(); k++)
		{
			matrix[j][k] -= matrix[startRow][k] * t;
		}
	}
}

double DeterminantCalculator::determinateOfTriangleMatrix(const Matrix& matrix) {
	double determinant = matrix[0][0];
	for(size_t i = 1; i < matrix.getRowsCount(); i++)
	{
		determinant *= matrix[i][i];
	}

	return determinant;
}